package org.lestr.secuel.sogl;

import java.util.ArrayList;
import java.util.Collection;

import org.lestr.secuel.m3ds.Camera;
import org.lestr.secuel.m3ds.Univers;
import org.lestr.secuel.m3ds.Variable;
import org.lestr.secuel.m3ds.lumieres.Lumiere;
import org.lestr.secuel.m3ds.objets3D.IObjet3d;
import org.lestr.secuel.m3ds.sons.Son;
import org.lestr.secuel.sogl.lumieres.SOGLLumiere;


public class SOGLUnivers implements Univers {

	
	// Déclaration des attributs
	private String nom;
	private Collection<IObjet3d> objets3D;
	private Collection<Lumiere> lumières;
	private Collection<Camera> caméras;
	private Collection<Son> sons;
	private Collection<Variable> variables;
	private boolean[] lumièresId;
	private Collection<UniversEcouteur> écouteurs;

	
	/** Constructeur */
	public SOGLUnivers(){
	
		// Instanciation des attributs
		nom = "Nouvel univers";
		objets3D = new ArrayList<IObjet3d>();
		lumières = new ArrayList<Lumiere>();
		sons = new ArrayList<Son>();
		caméras = new ArrayList<Camera>();
		variables = new ArrayList<Variable>();
		lumièresId = null;
		écouteurs = new ArrayList<UniversEcouteur>();
		
		// Ajoute une caméra à l'univers
		Camera caméra = Usine.getSingleton().caméra();
		ajoutCaméra(caméra);
		
	}// FIN SOGLUnivers
	
	
	/** Défini le nombre maximal de lumières */
	public void setNbLumièresMax(int max){
		
		// Si le tableau des indentifiants de lumières n'a pas encore été initialisé
		if(lumièresId == null){
			
			// L'initialise
			lumièresId = new boolean[max];
			
			// Aucune lumière pour l'instant
			for(int i = 0 ; i <= max - 1 ; i = i + 1)
				lumièresId[i] = false;
			
		}
		
	}// FIN setNbLumièresMax
	
	
	/** Ajoute un écouteur */
	public void ajoutEcouteur(UniversEcouteur écouteur){

		écouteurs.add(écouteur);
		
	}// FIN ajoutEcouteur
	
	
	/** Retire un écouteur */
	public void retraitEcouteur(UniversEcouteur écouteur){
		
		écouteurs.remove(écouteur);
		
	}// FIN retraitEcouteur
	
	
	/** Défini le nom de l'univers */
	public void setNom(String nom){
		
		// Si le nom change vraiement
		if(!this.nom.equals(nom)){
		
			// Mémorise
			String ancienNom = this.nom;
			this.nom = nom;
			
			// Prévient les écouteurs
			for(UniversEcouteur écouteur : écouteurs)
				écouteur.nomChangé(this, ancienNom);
		
		}
		
	}// FIN setNom
	
	
	/** Retourne le nom de l'univers */
	public String getNom(){
		
		return nom;
		
	}// FIN obtenirNom
	
	
	/** Défini les variables de l'univers */
	public void setVariables(Collection<Variable> variables){
		
		this.variables = variables;
		
	}// FIN setVariables
	
	
	/** Retourne les variables de l'univers */
	public Collection<Variable> getVariables(){
		
		return variables;
		
	}// FIN getVariables

	
	/** Ajoute un objet 3D à l'univers */
	public void ajoutObjet3D(IObjet3d objet){
		
		// Ajoute
		objets3D.add(objet);
		
		// Prévient les écouteurs
		for(UniversEcouteur écouteur : écouteurs)
			écouteur.objet3DAjouté(this, objet);
		
	}// FIN ajoutObjet3D

	
	/** Retire un objet 3D de l'univers */
	public void retraitObjet3D(IObjet3d objet){
		
		// Retire
		objets3D.remove(objet);
		
		// Prévient les écouteurs
		for(UniversEcouteur écouteur : écouteurs)
			écouteur.objet3DRetiré(this, objet);
		
	}// FIN retraitObjet3D
	
	
	/** Retourne les objets 3D de l'univers */
	public Iterable<IObjet3d> getObjets3D(){
		
		return objets3D;
		
	}// FIN getObjets3D
	
	
	/** Ajoute une lumière à l'univers */
	public void ajoutLumière(Lumiere lumière){
		
		// Si la lumière est déjà présente ne l'ajoute pas
		if(lumières.contains(lumière))
			return;
		
		// Si c'est un lumière SOGL
		if(lumière instanceof SOGLLumiere){

			// Choisi un identifiant de lumière
			int id = -1;
			for(int i = 0 ; i <= lumièresId.length - 1 ; i = i + 1)
				if(!lumièresId[i]){
					lumièresId[i] = true;
					id = i;
					break;
				}
			
			// Si un identifiant a été obtenu
			if(id != -1){
				
				// Donne l'identifiant à la lumière
				((SOGLLumiere) lumière).defId(id);
				
				// Ajoute la lumière
				lumières.add(lumière);
				
				// Prévient les écouteurs
				for(UniversEcouteur écouteur : écouteurs)
					écouteur.lumièreAjoutée(this, lumière);
				
			}
			
		}
		
	}// FIN ajoutLumière
	
	
	/** Retire une lumière de l'univers */
	public void retraitLumière(Lumiere lumière){
		
		// Si c'est un lumière SOGL
		if(lumière instanceof SOGLLumiere){
			
			// Rend l'identifiant
			lumièresId[((SOGLLumiere) lumière).getId()] = false;
			
			// Retire la lumière
			lumières.remove(lumière);
			
			// Prévient les écouteurs
			for(UniversEcouteur écouteur : écouteurs)
				écouteur.lumièreRetirée(this, lumière);
			
		}
		
	}// FIN retraitLumière
	
	
	/** Retourne les lumières de l'univers */
	public Iterable<Lumiere> getLumières(){
		
		return lumières;
		
	}// FIN getLumières
	
	
	/** Ajoute un son à l'univers */
	public void ajoutSon(Son son){
		
		// Ajoute
		sons.add(son);
		
		// Prévient les écouteurs
		for(UniversEcouteur écouteur : écouteurs)
			écouteur.sonAjouté(this, son);
		
	}// FIN ajoutSon
	
	
	/** Retire un son de l'univers */
	public void retraitSon(Son son){
		
		// Retire
		sons.remove(son);
		
		// Prévient les écouteurs
		for(UniversEcouteur écouteur : écouteurs)
			écouteur.sonRetiré(this, son);
		
	}// FIN retraitSon
	
	
	/** Retourne les sons de l'univers */
	public Iterable<Son> getSons(){
		
		return sons;
		
	}// FIN getSons


	@Override
	public void ajoutCaméra(Camera caméra) {
		
		// Ajoute
		caméras.add(caméra);
		
		// Prévient les écouteurs
		for(UniversEcouteur écouteur : écouteurs)
			écouteur.caméraAjoutée(this, caméra);
		
	}// FIN ajoutCaméra
	
	
	@Override
	public void retraitCaméra(Camera caméra){
		
		// Retire
		caméras.remove(caméra);
		
		// Prévient les écouteurs
		for(UniversEcouteur écouteur : écouteurs)
			écouteur.caméraRetirée(this, caméra);
		
	}// FIN retraitCaméra


	@Override
	public Iterable<Camera> getCaméras() {
		
		return caméras;
		
	}// FIN getCaméras
	

}// FIN Classe
